////////////////////////////////////////////////////////////////////////////////
// File:        TNod.cpp
// Purpose:     Implements TNod class for getting licenses and update TNod data
// Author:      Tukero
// Modified by: 
// Copyright:   (c) Tukero <tukero@gmail.com>
// Licence:     GNU/LGPL v3
////////////////////////////////////////////////////////////////////////////////

#include <wx/regex.h>            //regular expressions to make our life more confortable
#include <wx/file.h>             //files management (for debug)
#include <wx/tokenzr.h>          //tokens to String management
#include <wx/txtstrm.h>
#include <wx/platinfo.h>
#include <wx/datetime.h>

#include "TNod.h"
#include "CurrentAppHeaders.h"
#include "wx/httpbuilder.h"
#include "LicenseChecking.h"
#include "Settings.h"
#include "UpdatesChecker.h"

#define DONTWANT_RunNonElevated
#define NO_DLL_IMPORTS
#include "VistaTools.cxx"

//
// Loads the eset information and loads the server to check the TNod data (new versions, new license servers, etc)
//
TNod::TNod(EsetManager *esetManager) : TNodBase()
{
    wxDELETE( m_EsetInfo )
    
    m_EsetManager = esetManager;
    m_EsetInfo = m_EsetManager;
   
    m_hostName = SETTINGS->GetServer();
    m_hostPath = SETTINGS->GetServerPath();

    m_License2Insert = NULL;    
}

TNod::TNod() : TNodBase()
{
    wxDELETE( m_EsetInfo )
    
    m_EsetManager = new EsetManager();
    m_EsetManager->LoadInfo();
    m_EsetInfo = m_EsetManager;
   
    m_hostName = SETTINGS->GetServer();
    m_hostPath = SETTINGS->GetServerPath();

    m_License2Insert = NULL;    
}

//
// Updates TNod Data, inserts a new license and warning if a new version appears
//
void TNod::Start()
{
    NewVersionMsg *newVersionMsg = new NewVersionMsg();
    
    if ( m_Actions2Do == INSERT_LICENSE )
    {
        if ( m_License2Insert != NULL )
            InsertLicenseNow(*m_License2Insert);
        return;
    }   

    wxGetApp().ChangeMsgBalloon(1,GETLANG(69),true); //connecting message
    //UpdateTNodData(m_Actions2Do, newVersionMsg);
    if ( (m_Actions2Do & CHECK_UPDATES) == CHECK_UPDATES )
    {
        UpdatesChecker* newUpdatesChecker = new UpdatesChecker( newVersionMsg, m_EsetInfo, wxTHREAD_JOINABLE );
        newUpdatesChecker->SetNewVersionIndicator( &wxGetApp().m_NewVersionFound );
        newUpdatesChecker->LoadActions2Do(); //loads saved settings
        
        if ( newUpdatesChecker->Create() == wxTHREAD_NO_ERROR )
        {
            newUpdatesChecker->Run();
            newUpdatesChecker->Wait();
        }        
        delete newUpdatesChecker;
    }

    bool downloadMode = ((wxGetApp().m_ExtraModes & DOWNLOADMODE) == DOWNLOADMODE);
    //int insertType = wxConfig::Get()->Read(wxT("InsertType"), 0L);
    int insertType = SETTINGS->GetInsertType();
    int totalValidServers = 0;

    License excludeLicense;                    //the license which will be ignored in the checking

    if ( insertType == 2 && !downloadMode ) //insertion type 2: this program doesn't insert a license if the current is still valid
    {
        License currentLicense;
        m_EsetManager->GetCurrentLicense(currentLicense);
        
        if ( IsValidLicense(currentLicense) )
        {
            //if ( wxConfig::Get()->Read(wxT("InsertIfExpireNear"),1L) == 1L )
            if ( SETTINGS->InsertIfExpireNear() == true )
            {
                wxGetApp().ChangeMsgBalloon(1,GETLANG(68) + currentLicense.GetUsername(),true); //checking expiration date. message
                CheckExpiration(currentLicense);                                                 //checks the expiration date and expiration state
                if ( currentLicense.GetExpirationState() == 0 )                                    //if the state is 0 (is Ok)
                {                   
                    wxString message2Show = GETLANG(67);
                    message2Show.Replace(wxT("%t1"),currentLicense.GetUsername());

                    wxGetApp().ChangeMsgBalloon(1,message2Show);
                    ProcessNewVersionMsg(newVersionMsg);
                    return;
                }
            }
            else
            {
                wxString message2Show = GETLANG(67);
                message2Show.Replace(wxT("%t1"),currentLicense.GetUsername());

                wxGetApp().ChangeMsgBalloon(1,message2Show);
                ProcessNewVersionMsg(newVersionMsg);
                return;
            }
        }
    }
    else if ( insertType == 1 && !downloadMode )  //insertion type 1: always inserts a diferent license
        m_EsetManager->GetCurrentLicense(excludeLicense);//to exclude the current license
    
    //download licenses
    //if ( (wxGetApp().m_ExtraModes & EXPIREMODE) == EXPIREMODE )
    //    m_Actions2Do |= CHECK_EXPIRATION;
    
    FindLicenses(&m_ValidLicenses,&excludeLicense, &totalValidServers);
    
    if ( m_ValidLicenses.GetCount() > 0 ) //if the list contains licenses
    {
        bool insertLicense = true;
        if ( downloadMode )
        {
            insertLicense = false;
            /*
            if ( (m_Actions2Do & CHECK_EXPIRATION) == CHECK_EXPIRATION )
                CreateLicenseThreads(&m_ValidLicenses,LicenseChecking::CHECK_EXPIRATIONDATE);
            */
            if ((wxGetApp().m_ExtraModes & DOWNLOADDLGMODE) != DOWNLOADDLGMODE)
                 SaveLicenses(&m_ValidLicenses);
            else
                wxGetApp().ChangeMsgBalloon(1,GETLANG(70),true);
        }

        if ( (wxGetApp().m_ExtraModes & EXPIREMODE) == EXPIREMODE )
        {
            insertLicense = false;
            InsertLicenseNow(*GetLongestExpirationDate(&m_ValidLicenses));
        }

        if ( insertLicense )
            InsertLicenseNow(*m_ValidLicenses.GetFirst()->GetData());
    }    
    else if ( (m_Actions2Do & GET_LICENSE) == GET_LICENSE )
    {
        if ( totalValidServers == 0 )
            wxGetApp().ChangeMsgBalloon(3,GETLANG(146));//no servers available.message
        else
            wxGetApp().ChangeMsgBalloon(3,GETLANG(145)); //license not found. message
    }

    ProcessNewVersionMsg(newVersionMsg);
}

//
// Returns the license with the major expiration date
//
License * TNod::GetLongestExpirationDate(LinkListLicense *validLicenses)
{
    
    LinkListLicense::iterator iter;
    License *license = NULL;
    License *selectedLicense = validLicenses->GetFirst()->GetData();

    //*CreateLicenseThreads(validLicenses,LicenseChecking::CHECK_EXPIRATIONDATE);

    //now checks for the license with the major expiration date
    for (iter = validLicenses->begin(); iter != validLicenses->end() && !TestDestroy(); ++iter)
    {
        license = *iter;
        if ( license != NULL && license->GetExpirationDate() > selectedLicense->GetExpirationDate() )
            selectedLicense = license;
    }
    return selectedLicense;
}

//
// Creates one thread to check the expiration date, and waits for the thread termination
//
void TNod::CheckExpiration(License &license)
{    
    LicenseChecking *newChecking = new LicenseChecking(-1,&license,NULL,NULL/*,false*/,m_EsetManager,LicenseChecking::CHECK_EXPIRATIONDATE,wxTHREAD_JOINABLE);
    if ( newChecking->Create() == wxTHREAD_NO_ERROR )
    {
        newChecking->Run();
        newChecking->Wait();
    }
    delete newChecking;
}

//
// Checks the validity and the expiration, if both are valid, fills the validLicenses
//
void TNod::CheckValidityAndExpiration(PassServer *server, LinkListLicense *validLicenses,License *excludedLicense , int maxValidLicenses, bool licWithNoExpirationOnly)
{
    if ( server && validLicenses )
        CreateLicenseThreads(&server->licenseList,LicenseChecking::CHECK_VALIDITY|LicenseChecking::CHECK_EXPIRATIONDATE,validLicenses,excludedLicense,maxValidLicenses,licWithNoExpirationOnly);
}


void TNod::CheckLicensesList(PassServer *server, LinkListLicense *validLicenses, License * excludedLicense)
{
    if ( (wxGetApp().m_ExtraModes & DOWNLOADMODE) == DOWNLOADMODE)
    {
        if ( (m_Actions2Do & CHECK_EXPIRATION) == CHECK_EXPIRATION )
            CheckValidityAndExpiration(server, validLicenses, excludedLicense, wxGetApp().m_validLicenses2Get, false);
        else
            CheckValidityOfLicenses(server,validLicenses,excludedLicense,wxGetApp().m_validLicenses2Get);
    }
    else if ( (wxGetApp().m_ExtraModes & EXPIREMODE) == EXPIREMODE )
    {
        CheckValidityAndExpiration(server, validLicenses, excludedLicense, wxGetApp().m_validLicenses2Get, true);
    }
    else
    {
        if ( SETTINGS->AvoidNearExpiration() )
            CheckValidityAndExpiration(server,validLicenses,excludedLicense,wxGetApp().m_validLicenses2Get, true);
        else
            CheckValidityOfLicenses(server,validLicenses,excludedLicense,wxGetApp().m_validLicenses2Get);
    }
}

// ------------------------------------------------------------------------------------------------------------------------
// Inserts the license
// ------------------------------------------------------------------------------------------------------------------------
void TNod::InsertLicenseNow(License& license)
{
    wxGetApp().ChangeMsgBalloon(1,GETLANG(64),true); //entering license. message        
    
    int errorNum = m_EsetManager->InsertLicense(license,this); //inputs the license data and gets an error code for shows respective messages   
    /*if ( errorNum == 3 ) //if the error is #3, retry
    {
        wxGetApp().ChangeMsgBalloon(3, GETLANG(144),true ); 
        tkSleep(2000);

        wxGetApp().ChangeMsgBalloon(1,wxT("* ") + GETLANG(64), true);                //entering license. message

        errorNum = m_EsetManager->InsertLicense(license,this);
    }*/
    
    for (int c=0;c<2 && errorNum == 3;c++)//retry two times
    {
        wxGetApp().ChangeMsgBalloon(3, GETLANG(144),true ); 
        tkSleep(2000 - c*500);

        wxGetApp().ChangeMsgBalloon(1, (c == 0? wxT("* ") : wxT("- ")) + GETLANG(64), true); //entering license. message

        errorNum = m_EsetManager->InsertLicense(license,this);
    }
    
    if ( errorNum == 0 )      { wxGetApp().ChangeMsgBalloon(1, GETLANG(63) ); }//The license has been inserted correctly. message
    else if ( errorNum == 1 ) { wxGetApp().ChangeMsgBalloon(1, GETLANG(62) ); }//you already have lastest license. message
    else if ( errorNum == 2 ) { wxGetApp().ChangeMsgBalloon(3, GETLANG(143) ); }//antivirus isn't opened. message
    else if ( errorNum == 3 ) { wxGetApp().ChangeMsgBalloon(3, GETLANG(144) ); }//error trying inserting license. message    
    else if ( errorNum == 4 ) { wxGetApp().ChangeMsgBalloon(3, GETLANG(150) ); }//password used to modify settings isn't correct. message
    else if ( errorNum == 5 ) { wxGetApp().ChangeMsgBalloon(3, GETLANG(151) ); }//can't modify license data. message
    else if ( errorNum == 6 ) { wxGetApp().ChangeMsgBalloon(3, GETLANG(152) ); }//can't insert license because nod32 settings are protected by password.message
    else if ( errorNum == 7 ) 
    {
        bool elevated = !IsVista() || (IsVista() && IsElevated() == S_OK);
        if ( m_EsetManager->GetNodState() && !elevated )// == EsetInfo::NOD_OLDVERSION && !elevated )
        {
            BOOL result =   RunElevated(NULL,
                            Utils::GetExePath(),
                            wxT("/g ") + license.GetUsername() + wxT(" ") + license.GetPassword());

            if ( result == FALSE )//if the user denies the administrator rights
            {
                wxGetApp().ChangeMsgBalloon(3, GETLANG(153));//administrator rights is required.message
                return;
            }
            else
            {
                bool inserted = m_EsetManager->WaitInsertion(license);
                if ( inserted )
                    wxGetApp().ChangeMsgBalloon(1, GETLANG(63) );//The license has been inserted correctly. message
                else
                    wxGetApp().ChangeMsgBalloon(3, GETLANG(151) );//can't modify license data. message
            }
        }
        else
            wxGetApp().ChangeMsgBalloon(3, GETLANG(151) ); //can't modify license data. message
    }
    else if ( errorNum == 8 )
    {
        wxGetApp().ChangeMsgBalloon(3, GETLANG(153));//administrator rights is required.message
    }

}

// ------------------------------------------------------------------------------------------------------------------------
// Saves the licenses in a file
// ------------------------------------------------------------------------------------------------------------------------
void TNod::SaveLicenses(LinkListLicense *validLicenses)
{
    LinkListLicense::iterator iter;
    License *currLicense = NULL;
    wxString contentOfFile;

    wxFile file4License(wxGetApp().m_file2SaveLicenses,wxFile::write_append);
    if ( file4License.IsOpened() )
    {
        unsigned int licensesSaved = 0;
        for (iter = validLicenses->begin(); iter != validLicenses->end() && licensesSaved < wxGetApp().m_validLicenses2Get; ++iter, licensesSaved++)
        {
            currLicense = *iter;

            contentOfFile = wxT("Username: ") + currLicense->GetUsername() + wxT("\r\nPassword: ") + currLicense->GetPassword() + wxT("\r\n\r\n");

            file4License.Write(contentOfFile);
        }
        file4License.Close();
    }
}

// ------------------------------------------------------------------------------------------------------------------------
// Initializations
// ------------------------------------------------------------------------------------------------------------------------
void *TNod::Entry()
{
    if ( (wxGetApp().m_ExtraModes & INITMODE) == INITMODE && m_IsMain == true )
    {
        //an attempt every second
        for (int attempts = 0; !Utils::IsConnectionAvailable(SETTINGS->GetProxySettings()) && attempts < SETTINGS->GetSecsWaitForInternet() && !TestDestroy(); attempts++)
        {
            this->Sleep(1000);
        }
        /*
        for (int attempts = 0; !Utils::IsConnectionAvailable(SETTINGS->GetProxySettings()) && attempts < 30 && !TestDestroy(); attempts++)
            this->Sleep(3000);
        */

        if ( Utils::IsConnectionAvailable(SETTINGS->GetProxySettings()) )
        {
            //waits for the Antivirus Window
            for (int c=0;c < 5 && FindWindow(wxT("ESET Client Frame"),0) == NULL && !TestDestroy(); c++)
                wxThread::Sleep(1000);
        }
    }
    if ( !Utils::IsConnectionAvailable( SETTINGS->GetProxySettings() ) )
    {
        wxGetApp().ChangeMsgBalloon(3,GETLANG(147));//no internet connection. message
        return NULL;
    }
    else if ( !m_EsetManager->IsEsetInstalled() && ( wxGetApp().m_ExtraModes & DOWNLOADMODE ) != DOWNLOADMODE )
    {
        wxGetApp().ChangeMsgBalloon(3,GETLANG(139));//nod32 is not detected
        return NULL;
    }

    if ( m_Actions2Do == 0 )
        m_Actions2Do = ALL_ACTIONS;

    Start();
    return NULL;
}
